module branch_predict_competition (
    input wire clk, rst,
    
    input wire flushD,
    input wire stallD,

    input wire [31:0] pcF,
    input wire [31:0] pcM,

    input wire branchM,         // M阶段是否是分支指令
    input wire actual_takeM,    // 实际是否跳转

    input wire isWrong,
    input wire branchD,        // 译码阶段是否是跳转指令   
    output wire pred_takeD      // 预测是否跳转
);

    wire pred_takeE_local;
    wire pred_takeM_local;
    wire pred_takeE_global;
    wire pred_takeM_global;


    // 全局错 -> 全局对
    parameter Strongly_not_taken = 2'b00, Weakly_not_taken = 2'b01, Weakly_taken = 2'b11, Strongly_taken = 2'b10;


// ---------------------------------------预测值寄存器---------------------------------------

	floprc #(1) r1E(clk,rst,0,pred_takeD,pred_takeE);
	floprc #(1) r2E(clk,rst,0,pred_takeE,pred_takeM);

// ---------------------------------------预测值寄存器---------------------------------------


// ---------------------------------------预测逻辑---------------------------------------
  
    assign BHT_index = pcF[11:2];
    
    mux2 m1(pred_takeD_local,pred_takeD_global,CHT[BHT_index][1],pred_takeD);

// ---------------------------------------预测逻辑---------------------------------------


// ---------------------------------------初始化以及更新---------------------------------------
    parameter CHT_DEPTH = 10;
    integer i;

    wire[9:0] update_CHT_index;
    reg [1:0] CHT[(1<<CHT_DEPTH)-1 : 0];

    assign update_BHT_index = pcM[11:2];

    always @(posedge clk) begin
        
        if(rst) begin
            for(i = 0; i < (1<<CHT_DEPTH); i=i+1) begin
                CHT[i] <= Weakly_taken;
            end
        end
        // 只有两者预测不一样才需要更新
        else if (pred_takeM_local!=pred_takeM_global) begin
            case(CHT[update_CHT_index])
                Strongly_not_taken: 
                    if (pred_takeM_global==actual_takeM) begin
                        CHT[update_CHT_index]<=Weakly_not_taken;
                    end
                Weakly_not_taken: 
                    if (pred_takeM_global==actual_takeM) begin
                        CHT[update_CHT_index]<=Weakly_taken;
                    end
                    else begin
                        CHT[update_CHT_index]<=Strongly_not_taken;
                    end
                Weakly_taken: 
                    if (pred_takeM_global==actual_takeM) begin
                        CHT[update_CHT_index]<=Strongly_taken;
                    end
                    else begin
                        CHT[update_CHT_index]<=Weakly_not_taken;
                    end
                Strongly_taken: 
                    if (!(pred_takeM_global==actual_takeM)) begin
                        CHT[update_CHT_index]<=Weakly_taken;
                    end
            endcase 
        end
    end

// ---------------------------------------初始化以及更新---------------------------------------


// ---------------------------------------调用两个预测得到结果---------------------------------------

    wire pred_takeD_local;
    wire pred_takeD_global;

	branch_predict_local bpl(
		clk, rst,

		flushD,
		stallD,

		pcF,
		pcM,

		branchM,         // M阶段是否是分支指令
		actual_takeM,    // 实际是否跳转

		branchD,        // 译码阶段是否是跳转指令   
		pred_takeD_local      // 预测是否跳转
	);

	branch_predict_global bpg(
		clk, rst,

		flushD,
		stallD,

		pcF,
		pcM,

		branchM,         // M阶段是否是分支指令
		actual_takeM,    // 实际是否跳转
        
        isWrong,
		branchD,        // 译码阶段是否是跳转指令   
		pred_takeD_global      // 预测是否跳转
	);

// ---------------------------------------调用两个预测得到结果---------------------------------------

endmodule